#region (c) 2014 THN Solutions LLC. - All rights reserved
/*
THN DATA ABSTRACTION LAYER version 1

Copyright (c) 2014, THN Solutions LLC. ( www.ThnSolutions.com )
Author: Nguyễn, M. Hải                 ( www.Minh-Hai.com     )
All rights reserved.

This library is dual-licensed.
  + For commercial software, please obtain a commercial license from THN Solutions LLC.

  + For free software, this library is licensed under GPL version 3. A summary of GPLv3 is
    listed below. You should also find a copy of GPLv3 as file License_GPLv3.txt included
	with the source-code files.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License version 3 as published by
    the Free Software Foundation  of the License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#endregion
#region Using directives
using System;
using Thn.Application;
#endregion

namespace Thn.Data
{
    /// <summary>
    /// Most basic condition. Provides a simple comparision between a field and a value.
    /// Supported operators:
	/// <para>Condition A & Condition B => NestedCondition(A AND B)</para>
	/// <para>Condition A & Condition B => NestedCondition(A OR B)</para>
    /// </summary>
    [Serializable]
    public class SingleCondition: Condition
    {
        #region Properties
		#region Field
		string mField = "";
        /// <summary>
        /// Gets or Sets the field name this condition applies to
        /// </summary>
        [Savable]
        public string Field
        {
            get { return mField; }
            set { mField = value; }
		}
		#endregion

		#region Operation
		ComparisionType mOperation = ComparisionType.Equal;
        /// <summary>
        /// Gets or Sets the operation type 
        /// </summary>
        [Savable]
        public ComparisionType Operation
        {
            get { return mOperation; }
            set { mOperation = value; }
		}
		#endregion

		#region Value
		IComparable mValue = null;
        /// <summary>
        /// Gets or Sets the value to compare to
        /// </summary>
        [Savable]
        public IComparable Value
        {
            get { return mValue; }
            set { mValue = value; }
		}
		#endregion

		#region ErrorMessage
		private string mErrorMessage = "";
		/// <summary>
		/// Gets/Sets the message to be shown when this condition is not matched
		/// </summary>
		public string ErrorMessage
		{
			get { return mErrorMessage; }
			set { mErrorMessage = value; }
		}
		#endregion
        #endregion

        #region Constructor
        /// <summary>
        /// Creates an equal comparision: A = SomeValue
        /// </summary>
        public SingleCondition(string fieldName, IComparable CompareValue)
        {
            mField = fieldName;
            mValue = CompareValue;
            mOperation = ComparisionType.Equal;
        }

		/// <summary>
		/// Create a new instance
		/// </summary>
		public SingleCondition(string fieldName, IComparable CompareValue, ComparisionType Operation)
		{
			mField = fieldName;
			mValue = CompareValue;
			mOperation = Operation;
		}

		/// <summary>
		/// Create a new instance
		/// </summary>
        public SingleCondition(string fieldName, IComparable CompareValue, ComparisionType Operation, string errorMessage)
        {
            mField = fieldName;
            mValue = CompareValue;
            mOperation = Operation;
			mErrorMessage = errorMessage;
        }

		/// <summary>
		/// Create a new instance
		/// </summary>
        public SingleCondition()
        {
        }
        #endregion

        #region Operators overload
		/// <summary>
		/// Combine two conditions by AND operation
		/// </summary>
        public static Condition operator &(SingleCondition c1, SingleCondition c2)
        {
			if (c1 == null) return c2;
			else if (c2 == null) return c1;
            else return new NestedCondition(c1, c2, CombinationType.And);
        }

		/// <summary>
		/// Combine two conditions by AND operation
		/// </summary>
		public static Condition operator &(NestedCondition c1, SingleCondition c2)
        {
			if (c1 == null) return c2;
			else if (c2 == null) return c1;
			else return new NestedCondition(c1, c2, CombinationType.And);
        }

		/// <summary>
		/// Combine two conditions by AND operation
		/// </summary>
		public static Condition operator &(SingleCondition c1, NestedCondition c2)
        {
			if (c1 == null) return c2;
			else if (c2 == null) return c1;
			else return new NestedCondition(c1, c2, CombinationType.And);
        }

		/// <summary>
		/// Combine two conditions by OR operation
		/// </summary>
		public static Condition operator |(SingleCondition c1, SingleCondition c2)
        {
			if (c1 == null) return c2;
			else if (c2 == null) return c1;
			else return new NestedCondition(c1, c2, CombinationType.Or);
        }

		/// <summary>
		/// Combine two conditions by OR operation
		/// </summary>
		public static Condition operator |(NestedCondition c1, SingleCondition c2)
        {
			if (c1 == null) return c2;
			else if (c2 == null) return c1;
			else return new NestedCondition(c1, c2, CombinationType.Or);
        }

		/// <summary>
		/// Combine two conditions by OR operation
		/// </summary>
		public static Condition operator |(SingleCondition c1, NestedCondition c2)
        {
			if (c1 == null) return c2;
			else if (c2 == null) return c1;
			else return new NestedCondition(c1, c2, CombinationType.Or);
        }

        ///// <summary>
        ///// Equality
        ///// </summary>
        //public static bool operator ==(SingleCondition c1, SingleCondition c2)
        //{
        //    if ((c1 == null) && (c2 == null)) return true;
        //    else return c1.Equals(c2);
        //}

        ///// <summary>
        ///// Inequality
        ///// </summary>
        //public static bool operator !=(SingleCondition c1, SingleCondition c2)
        //{
        //    return !c1.Equals(c2);
        //}
        #endregion

        #region Equals
		/// <summary>
		/// Equality
		/// </summary>
        public override bool Equals(object obj)
        {
            bool equal = false;

            if (obj is SingleCondition)
            {
                SingleCondition con = (SingleCondition)obj;
                if (con.mValue == null) equal = (con.mField.Equals(mField)) && (con.mOperation.Equals(mOperation));
                else equal = (con.mField.Equals(mField)) && (con.mOperation.Equals(mOperation)) && (con.mValue.Equals(mValue));
            }
            return equal;
        }

        /// <summary>
        /// Gets ID of this object
        /// </summary>
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
        #endregion

        #region ToString
		/// <summary>
		/// Converts to string
		/// </summary>
        public override string ToString()
        {
            string s="";
            switch (mOperation)
            {
                case ComparisionType.Equal:
                    s = "(" + mField + " = " + mValue.ToString() + ")";
                    break;
                case ComparisionType.Greater:
                    s = "(" + mField + " > " + mValue.ToString() + ")";
                    break;
                case ComparisionType.GreaterOrEqual:
                    s = "(" + mField + " >= " + mValue.ToString() + ")";
                    break;
                case ComparisionType.Less:
                    s = "(" + mField + " < " + mValue.ToString() + ")";
                    break;
                case ComparisionType.LessOrEqual:
                    s = "(" + mField + " <= " + mValue.ToString() + ")";
                    break;
                case ComparisionType.NotEqual:
                    s = "(" + mField + " <> " + mValue.ToString() + ")";
                    break;
				case ComparisionType.NotEmpty:
					s = "(" + mField + " is not empty)";
					break;
				case ComparisionType.Unique:
					s = "(" + mField + " is unique)";
					break;
            }
            return s;
        }

        #endregion
    }	
}
